<?php 
/** create by fu */
namespace app\api\service;

use app\lib\exception\OrderException;
use app\lib\exception\UserException;
use app\api\model\Product as ProductModel;
use app\api\model\OrderProduct as OrderProductModel;
use app\api\model\UserAddress;
use think\Db;
/**
 * @param oProducts = 1:3,2:3,3:3 
 * 此方法的精髓在于
 * 1 遍历购物车的所有商品ID 并查出所需要的商品详情【存入类属性】
 * 2 用 getOrderStatus 方法里 遍历 oProducts 获得第一维[pass orderPrice pStatusArray]
            foreach内部 使用 getProductStatus($oPID,$oCount,$products) 获得 pStatusArray=[ id         的数组
																						  haveStock
																						  count
																						  name
																						  totalPrice
																						] 
 */
class Order
{
	
	//订单的商品列表  客户端出过来的 商品id和购买数量的数组
	protected $oProducts;

	//真实的商品信息 （包括库存量）
	protected $products;

	protected $uid;

	public function place($uid,$oProducts)
	{
		//   和 products 

		$this->oProducts = $oProducts;
		// 获得数据表里真实的商品 ['id','price','stock','name','main_img_url']
		$this->products  = $this->getProductsByOrder($oProducts);
		$this->uid = $uid;

		$result = $this->getOrderStatus();

		// 无库存 不创建订单
		if(!$result['pass']){
			$result['order_id'] = -1;
            return $result;
		}else{
			//准备数据 订单 快照
			$orderSnap = $this->snapOrder($result);
			//写入订单
			$order     = $this->createOrder($orderSnap);
			$order['pass'] = true;
			return $order;
		}

	}
    
    /** 
     * 写入订单信息
     * @param snap 快照信息
     */
	private function createOrder($snap)
	{
		Db::startTrans();
		try{
			$orderNo = $this->makeOrderNo();
			$order = new \app\api\model\Order();
			$order->user_id = $this->uid;
			$order->order_no = $orderNo;
			$order->total_price = $snap['orderPrice'];
			$order->total_count = $snap['totalCount'];
			$order->snap_img = $snap['snapImg'];
			$order->snap_name = $snap['snapName'];
			$order->snap_address = $snap['snapAddress'];
			$order->snap_items = json_encode($snap['pStatus']);

			$order->save();
 			$orderID = $order->id;
			$create_time = $order->create_time;
	// 传引用将改变 赋值
			foreach ($this->oProducts as $key => &$p) {
				$p['order_id'] = $orderID;
			}

			$orderProduct = new OrderProductModel();
			$orderProduct->saveAll($this->oProducts);

	        Db::commit();
	        return [
	        	'order_no' => $orderNo,
	        	'order_id' => $orderID,
	        	'create_time' => $create_time,
	        ];
	    }
	    catch(Exception $ex){
	    	Db::rollback();
            throw $ex;
	    }

	}
 

	/**
	 * 生成订单快照
	 */
	private function snapOrder($status)
	{
		$snap = [
			'orderPrice' => 0,    // 商品总价格
			'totalCount' => 0,    // 订单商品总数量
			'pStatus'    => [],   // 所有商品状态
			'snapAddress'=> null, // 收货地址
			'snapName'   => '',   // 概要商品名称
			'snapImg'    => '',   // 概要商品图片
		];
		$snap['orderPrice'] = $status['orderPrice'];
		$snap['totalCount'] = $status['totalCount'];
		$snap['pStatus'] = $status['pStatusArray'];   //存['id','count','name','totalPrice','haveStock']
		$snap['snapAddress'] = json_encode($this->getUserAddress());
		$snap['snapName'] = $this->products[0]['name'];
		$snap['snapImg'] = $this->products[0]['main_img_url'];

		if(count($this->products) > 1)$snap['snapName'] .= '等';

		return $snap;

	}

	// 生成订单号
	public static function makeOrderNo()
	{
		$yCode = ['A','B','C','D','E','F','G','H','I','J'];
		$orderSn = 
		         $yCode[intval(date('Y'))-2017].
		         strtoupper(dechex(date('m'))).date('d').substr(time(), -5).
		         substr(microtime(),2,5).sprintf('%02d',rand(0,99));
		return $orderSn;
	}
	
	//获取用户地址
	private function getUserAddress()
	{
		$userAddress = UserAddress::where('user_id','=',$this->uid)->find();
// p($userAddress);
		if(!$userAddress)throw new UserException([
			'msg' => '用户收货地址不存在，下单失败',
			'errorCode' => 60001,
		]);

		return $userAddress->toArray();
	}

	/**  对比两个数组 oProducts  products 获得以下形式结果
	   array(3) {
				  ["pass"] => bool(true)
				  ["orderPrice"] => float(0.09)
				  ["pStatusArray"] => array(3) {
				    {
				      ["id"] => int(1)
				      ["haveStock"] => bool(true)
				      ["count"] => int(3)
				      ["name"] => string(13) "芹菜 半斤"
				      ["totalPrice"] => float(0.03)
				    }

				    {
				      ["id"] => int(2)
				      ["haveStock"] => bool(true)
				      ["count"] => int(3)
				      ["name"] => string(17) "梨花带雨 3个"
				      ["totalPrice"] => float(0.03)
				    }

				    {
				      ["id"] => int(3)
				      ["haveStock"] => bool(true)
				      ["count"] => int(3)
				      ["name"] => string(13) "素米 327克"
				      ["totalPrice"] => float(0.03)
				    }
				  }
				}
	 *
	 */
    private function getOrderStatus()
	{
		$status = [
			'pass'       => true, // 是否全部有库存
			'orderPrice' => 0,    // 统计总价格
			'totalCount' => 0,    // 共有几种商品
			'pStatusArray'=>[],   // 存['id','count','name','totalPrice','haveStock']
		];

		foreach ($this->oProducts as $oProduct) 
		{   
			//根据 oProduct_id，oCount 进入 products 里 计算价格 判断库存
			$pStatus = $this->getProductStatus($oProduct['product_id'],$oProduct['count'],$this->products);

			if(!$pStatus['haveStock'])$status['pass'] = false;

			$status['orderPrice'] += $pStatus['totalPrice'];
			$status['totalCount'] += $pStatus['count'];

			array_push($status['pStatusArray'], $pStatus);
		}

		return $status;
	}

    /**搜寻 oProducts传过来的商品ID 是否存在过滤过的数据库中的 ID
     * ['product_id','count']
     * products  ['id','price','stock','name','main_img_url']
     *
     */
	private function getProductStatus($oPID,$oCount,$products)
	{
		$pIndex = -1;

		$pStatus = [
			'id'        => null,
			'haveStock' => false,
			'count'     => 0,
			'name'      => '',
			'totalPrice'=> 0,
		];
        //判断是否有此商品
		for ($i=0; $i < count($products); $i++) { 
			if($oPID == $products[$i]['id']){
				$pIndex = $i;
			}
		}
        if($pIndex == -1) throw new OrderException(['msg'=>'抱歉商品ID为'.$oPID.'不存在']);
		$product = $products[$pIndex];

		$pStatus['id'] = $oPID;
		$pStatus['count'] = $oCount;
		$pStatus['name'] = $product['name'];
		$pStatus['totalPrice'] = $product['price']*$oCount;
		$pStatus['haveStock'] = (($product['stock']-$oCount) >= 0) ? true : false;

		return $pStatus;
	}

	// 根据订单信息查找真实的商品信息
	private function getProductsByOrder($oProducts)
	{
		// 注意不能使用foreach 遍历数据表 不然在购物车物品很多的时候 数据库容易挂
		// 先遍历所有的商品ID 
		$oPIDS = [];
		foreach ($oProducts as $item) {

			array_push($oPIDS, $item['product_id']);
		}

		// 根据得到的$oPIDS 查询真实商品信息 
		$products = ProductModel::all($oPIDS)
			      ->visible(['id','price','stock','name','main_img_url'])
			      ->toArray();

	    return $products;
	}

	// 对外进行库存量检测
	public function checkOrderStock($orderID)
	{
		//根据订单id 到表order_product 查出所有 商品id 购买数量 
		$oProducts = OrderProductModel::where('order_id','=',$orderID)->select();
		$this->oProducts = $oProducts;
        
        //根据数组 获得真实商品信息
        $this->products = $this->getProductsByOrder($oProducts);

        //获得订单信息
        $status = $this->getOrderStatus();

        return $status;
	}

}













 ?>